package cc.shacocloud.mirage.core;

import cc.shacocloud.mirage.bean.ConfigurableBeanFactory;
import cc.shacocloud.mirage.core.event.ContextFinishStartEvent;
import cc.shacocloud.mirage.env.ConfigurableEnvironment;
import cc.shacocloud.mirage.utils.FutureUtils;
import io.vertx.core.CompositeFuture;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Objects;

/**
 * 抽象的应用上下文，负责应用的整体逻辑实现
 *
 * @author 思追(shaco)
 */
@Slf4j
public abstract class AbstractApplicationContext implements ConfigurableApplicationContext {
    
    private ConfigurableBeanFactory configurableBeanFactory;
    
    private ConfigurableEnvironment configurableEnvironment;
    
    private ApplicationEventMulticaster applicationEventMulticaster;
    
    private long startupDate;
    
    @Nullable
    private Vertx vertx;
    
    public AbstractApplicationContext() {
        // 注册应用关机句柄
        Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
    }
    
    @Override
    public Vertx getVertx() {
        if (Objects.isNull(this.vertx)) {
            this.vertx = getBean(Vertx.class);
        }
        return this.vertx;
    }
    
    @Override
    public long getStartupDate() {
        return startupDate;
    }
    
    @NotNull
    @Override
    public ConfigurableBeanFactory getBeanFactory() {
        if (Objects.nonNull(this.configurableBeanFactory)) return this.configurableBeanFactory;
        
        this.configurableBeanFactory = doBeanFactory();
        return this.configurableBeanFactory;
    }
    
    /**
     * 获取对应的对象工厂 由子类提供
     */
    @NotNull
    protected abstract ConfigurableBeanFactory doBeanFactory();
    
    @NotNull
    @Override
    public ConfigurableEnvironment getEnvironment() {
        if (Objects.nonNull(this.configurableEnvironment)) return this.configurableEnvironment;
        
        this.configurableEnvironment = doEnvironment();
        return this.configurableEnvironment;
    }
    
    /**
     * 获取对应的环境配置对象 由子类提供
     */
    @NotNull
    protected abstract ConfigurableEnvironment doEnvironment();
    
    @Override
    public @NotNull ApplicationEventMulticaster getEventMulticaster() {
        if (Objects.nonNull(this.applicationEventMulticaster)) return this.applicationEventMulticaster;
        
        this.applicationEventMulticaster = doEventMulticaster();
        return this.applicationEventMulticaster;
    }
    
    /**
     * 获取对应的事件多播器对象 由子类提供
     */
    @NotNull
    protected abstract ApplicationEventMulticaster doEventMulticaster();
    
    @Override
    public void start() {
        this.startupDate = System.currentTimeMillis();
        
        // 加载对象工厂
        final ConfigurableBeanFactory beanFactory = getBeanFactory();
        
        // 加载环境配置
        final ConfigurableEnvironment environment = getEnvironment();
        
        // 环境配置初始化
        environment.init();
        
        // 初始化对象工厂
        beanFactory.init();
        
        // 初始化默认绑定
        initDefaultBind();
        
        // 发布上下文完成启动事件
        publishFinishStartEvent();
        
        // 完成启动
        finishStart();
        
        // 启动应用配置变更监听
        environment.startEnvironmentChangeMonitoring();
    }
    
    /**
     * 发布启动成功事件
     */
    protected void publishFinishStartEvent() {
        ApplicationEventMulticaster eventMulticaster = getEventMulticaster();
        
        Promise<Void> promise = Promise.promise();
        CompositeFuture compositeFuture = eventMulticaster.publishEvent(new ContextFinishStartEvent(this));
        
        compositeFuture.onComplete(ar -> {
            if (ar.succeeded()) {
                promise.complete();
            } else {
                
                if (log.isErrorEnabled()) {
                    CompositeFuture result = ar.result();
                    for (int i = 0; i < result.size(); i++) {
                        Throwable cause = result.cause(i);
                        if (Objects.isNull(cause)) continue;
                        
                        log.error("上下文事件监听器处理异常！", cause);
                    }
                }
                promise.fail("发布上下文启动完成事件出现例外！");
            }
        });
        
        // 等待执行完成
        FutureUtils.await(promise.future());
    }
    
    @Override
    public void stop() {
        Vertx vertx = getVertx();
        
        // 关闭 Vertx 对象
        FutureUtils.await(vertx.close());
    }
    
    /**
     * 初始化默认绑定，该方法在环境配置，对象工厂初始化完成后执行
     */
    protected void initDefaultBind() {
        // 注册基于应用上下文实现的 vertx VerticleFactory
        ApplicationContextVerticleFactory applicationContextVerticleFactory = getBean(ApplicationContextVerticleFactory.class);
        registerVerticleFactory(applicationContextVerticleFactory);
    }
    
    /**
     * 基本配置信息完成启动，提供一个拓展方法由子类完善
     */
    protected void finishStart() {
        if (log.isInfoEnabled()) {
            log.info("应用上下文启动完成");
        }
    }
    
}
